import * as vscode from 'vscode';
import * as path from 'path';

export class DbcEditorProvider implements vscode.CustomTextEditorProvider {
	public static readonly viewType = 'dbcEditor.editor';

	constructor(private readonly context: vscode.ExtensionContext) {}

	// 保存当前活动的编辑器，用于快捷键触发解析
	private static activeEditor: vscode.WebviewPanel | undefined;

	public async resolveCustomTextEditor(
		document: vscode.TextDocument,
		webviewPanel: vscode.WebviewPanel,
		_token: vscode.CancellationToken
	): Promise<void> {
		// 设置 Webview 选项
		webviewPanel.webview.options = {
			enableScripts: true,
		};

		// 保存当前活动的编辑器
		DbcEditorProvider.activeEditor = webviewPanel;

		// 设置 HTML 内容
		webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview, document);

		// 监听文档变化
		const changeDocumentSubscription = vscode.workspace.onDidChangeTextDocument((e: vscode.TextDocumentChangeEvent) => {
			if (e.document.uri.toString() === document.uri.toString()) {
				this.updateWebview(webviewPanel.webview, document);
			}
		});

		// 监听 Webview 消息
		webviewPanel.webview.onDidReceiveMessage(
			message => {
				switch (message.type) {
					case 'updateDocument':
						this.updateDocument(document, message.content);
						return;
					case 'save':
						this.downloadDbc(message.content, message.filename);
						return;
					case 'requestContent':
						// 响应适配器的内容请求
						this.updateWebview(webviewPanel.webview, document);
						return;
					case 'error':
						vscode.window.showErrorMessage(message.message);
						return;
				}
			},
			null,
			this.context.subscriptions
		);

		// 清理订阅
		webviewPanel.onDidDispose(() => {
			if (DbcEditorProvider.activeEditor === webviewPanel) {
				DbcEditorProvider.activeEditor = undefined;
			}
			changeDocumentSubscription.dispose();
		});
	}

	// 解析当前文件的方法，用于快捷键触发
	public parseCurrentFile(): boolean {
		if (!DbcEditorProvider.activeEditor) {
			vscode.window.showErrorMessage('没有活动的DBC编辑器');
			return false;
		}

		// 向webview发送解析命令
		DbcEditorProvider.activeEditor.webview.postMessage({
			type: 'parseFile'
		});
		
		return true;
	}

	private getHtmlForWebview(webview: vscode.Webview, document: vscode.TextDocument): string {
		const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'media', 'dbc-editor.js'));
		const adaptedScriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'media', 'dbc-editor-adapted.js'));
		const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'media', 'dbc-editor.css'));
		const themeStyleUri = webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'media', 'vscode-theme.css'));
		const documentContent = document.getText();
		const nonce = getNonce();

		return `<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" href="${styleUri}">
	<link rel="stylesheet" href="${themeStyleUri}">
	<title>DBC Editor</title>
</head>
<body>
	<div id="dbc-root">
		<header class="dbc-header">
			<button id="dbc-open-button" class="dbc-header-button" type="button">
				open DBC
			</button>
			<button id="dbc-download-button" class="dbc-header-button" type="button">
				download DBC
			</button>

			<input id="dbc-file-input" type="file" accept=".dbc" hidden />
			<p style="color:#787878;">
				DBC Editor v1.0.0 for VSCode
			</p>
		</header>

		<div id="dbc-can-messages-header" class="dbc-table-header">
			<div class="dbc-table-header-name">CAN messages</div>

			<div class="dbc-table-header-buttons">
				<span class="dbc-add-button" title="Add message">+</span>
				<span class="dbc-remove-button" title="Remove selected message">-</span>
			</div>
		</div>
		<div id="dbc-can-messages-container" class="dbc-table-container">
			<div class="dbc-scrollable-container dbc-v-scroll">
				<div class="dbc-v-scroll-line"></div>

				<div class="dbc-scrollable">
					<table id="dbc-can-messages-table" class="dbc-table">
						<thead id="dbc-can-messages-head">
							<tr>
								<th></th>
								<th></th>
								<th>Name</th>
								<th>
									CAN ID
									<select id="dbc-number-format-select" class="dbc-select">
										<option value="hex">HEX</option>
										<option value="dec">DEC</option>
									</select>
								</th>
								<th>Type</th>
								<th>DLC</th>
								<th>Comment</th>
							</tr>
						</thead>

						<tbody id="dbc-can-messages-body"></tbody>
					</table>
				</div>
			</div>
		</div>

		<div id="dbc-can-signals-header" class="dbc-table-header">
			<div class="dbc-table-header-name">
				CAN signals (<span class="dbc-selected-message-name"></span>)
			</div>

			<div class="dbc-table-header-buttons">
				<span class="dbc-add-button" title="Add signal">+</span>
				<span class="dbc-remove-button" title="Remove selected signal">-</span>
			</div>
		</div>
		<div id="dbc-can-signals-container" class="dbc-table-container">
			<div class="dbc-scrollable-container dbc-hv-scroll">
				<div class="dbc-h-scroll-line"></div>
				<div class="dbc-v-scroll-line"></div>

				<div class="dbc-scrollable">
					<table id="dbc-can-signals-table" class="dbc-table">
						<thead id="dbc-can-signals-head">
							<tr>
								<th></th>
								<th></th>
								<th>Name</th>
								<th>Type</th>
								<th>Order</th>
								<th>Mode</th>
								<th>Multiplexor</th>
								<th>Multiplex value</th>
								<th><abbr style="text-decoration: none !important; border: none !important;" title="The start bit shown in the editor equals the start bit of the DBC file. For Intel signals, this reflects the Least Significant Bit (LSB), while for Motorola, it reflects the Most Significant Bit (MSB)"> Start</abbr></th>
								<th>Length</th>
								<th>Factor</th>
								<th>Offset</th>
								<th>Min</th>
								<th>Max</th>
								<th>Unit</th>
								<th>Comment</th>
							</tr>
						</thead>

						<tbody id="dbc-can-signals-body"></tbody>
					</table>
				</div>
			</div>

			<div class="dbc-collapsible-header">
				<div class="dbc-collapsible-header-name dbc-colored">CAN signal preview</div>
				<div class="dbc-collapse-button dbc-collapsed"></div>
			</div>
			<div id="dbc-can-signal-preview" class="dbc-collapsible-area dbc-hidden">
				<div class="dbc-scrollable-container dbc-v-scroll">
					<div class="dbc-v-scroll-line"></div>

					<div class="dbc-scrollable">
						<div id="dbc-byte-number-container">
							<div id="dbc-byte-number">Byte number</div>
						</div>

						<div class="dbc-preview-layout">
							<div class="dbc-preview-column">
								<table id="dbc-bit-indices-table" class="dbc-mini-table">
									<thead id="dbc-bit-indices-head">
										<tr>
											<th></th>
											<th colspan="8" style="font-size: 18px; padding: 8px;">Editor bit indices</th>
										</tr>
										<tr>
											<th></th>
											<th>7</th>
											<th>6</th>
											<th>5</th>
											<th>4</th>
											<th>3</th>
											<th>2</th>
											<th>1</th>
											<th>0</th>

										</tr>
									</thead>
									<tbody id="dbc-bit-indices-body"></tbody>
								</table>
							</div>

							<div class="dbc-preview-column">
								<table id="dbc-can-frame-table" class="dbc-mini-table-can">
									<thead id="dbc-can-frame-head">
										<tr>
											<th></th>
											<th colspan="2">CAN frame</th>
											<th colspan="8">Bit data values</th>
										</tr>

										<tr>
											<th></th>
											<th>Data (HEX)</th>
											<th>Data (BIN)</th>
											<th>7</th>
											<th>6</th>
											<th>5</th>
											<th>4</th>
											<th>3</th>
											<th>2</th>
											<th>1</th>
											<th>0</th>
										</tr>
									</thead>

									<tbody id="dbc-can-frame-body"></tbody>
								</table>
							</div>

							<div class="dbc-preview-column">
								<table id="dbc-signal-mask-table" class="dbc-mini-table">
									<thead id="dbc-signal-mask-head">
										<tr>
											<th colspan="8">Signal mask (BIN)</th>
										</tr>

										<tr></tr>

										<tr>
											<th>7</th>
											<th>6</th>
											<th>5</th>
											<th>4</th>
											<th>3</th>
											<th>2</th>
											<th>1</th>
											<th>0</th>
										</tr>
									</thead>

									<tbody id="dbc-signal-mask-body"></tbody>
								</table>
							</div>
						</div>

						<div id="dbc-result-container" class="dbc-colored">
							<div>
								Data = 0x<span id="dbc-result-data-hex"></span> =
								<span id="dbc-result-data-dec"></span>
							</div>

							<div>
								Physical value = <span id="dbc-result-value-factor"></span> *
								<span id="dbc-result-value-dec"></span> +
								<span id="dbc-result-value-offset"></span> =
								<span id="dbc-result-value" class="dbc-bold"></span>
								<span id="dbc-result-value-unit" class="dbc-bold"></span>
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>

		<div id="dbc-preview-header" class="dbc-table-header">
			<div class="dbc-table-header-name">
				DBC preview (<span class="dbc-selected-message-name"></span>)
			</div>
		</div>
		<div id="dbc-preview-container" class="dbc-table-container">
			<div class="dbc-scrollable-container dbc-hv-scroll">
				<div class="dbc-h-scroll-line"></div>
				<div class="dbc-v-scroll-line"></div>

				<div class="dbc-scrollable">
					<pre id="dbc-preview"></pre>
				</div>
			</div>
		</div>

		<div id="dbc-modal-backdrop" class="dbc-invisible">
			<div id="dbc-modal">
				<div id="dbc-modal-close">x</div>
				<div id="dbc-modal-content"></div>
				<div id="dbc-modal-actions"></div>
			</div>
		</div>
	</div>

	<script nonce="${nonce}">
		const vscode = acquireVsCodeApi();
		window.file = ${JSON.stringify(documentContent)};
		window.filename = ${JSON.stringify(path.basename(document.uri.fsPath))};
	</script>
	<script src="${scriptUri}"></script>
	<script src="${adaptedScriptUri}"></script>
</body>
</html>`;
	}

	private updateWebview(webview: vscode.Webview, document: vscode.TextDocument) {
		const content = document.getText();
		const filename = path.basename(document.uri.fsPath);
		
		console.log(`Updating webview with content length: ${content.length}, filename: ${filename}`);
		
		// 立即发送文件内容，不要延迟
		webview.postMessage({
			type: 'updateContent',
			content: content,
			filename: filename
		});
	}

	private updateDocument(document: vscode.TextDocument, content: string) {
		const edit = new vscode.WorkspaceEdit();
		const fullRange = new vscode.Range(
			document.positionAt(0),
			document.positionAt(document.getText().length)
		);
		edit.replace(document.uri, fullRange, content);
		return vscode.workspace.applyEdit(edit);
	}

	private async downloadDbc(content: string, filename: string) {
		const saveUri = await vscode.window.showSaveDialog({
			defaultUri: vscode.Uri.file(filename),
			filters: {
				'DBC files': ['dbc'],
				'All files': ['*']
			}
		});

		if (saveUri) {
			const buffer = Buffer.from(content, 'utf8');
			await vscode.workspace.fs.writeFile(saveUri, buffer);
			vscode.window.showInformationMessage(`DBC file saved to ${saveUri.path}`);
		}
	}
}

function getNonce() {
	let text = '';
	const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
	for (let i = 0; i < 32; i++) {
		text += possible.charAt(Math.floor(Math.random() * possible.length));
	}
	return text;
} 